﻿namespace UnityEditor
{
    using System;
    using System.Collections.Generic;
    using UnityEngine;

    internal class NormalCurveRenderer : CurveRenderer
    {
        private AnimationCurve m_Curve;
        private float m_CustomRangeEnd;
        private float m_CustomRangeStart;
        private int m_SegmentResolution = 20;
        private WrapMode postWrapMode = WrapMode.Once;
        private WrapMode preWrapMode = WrapMode.Once;

        public NormalCurveRenderer(AnimationCurve curve)
        {
            this.m_Curve = curve;
            if (this.m_Curve == null)
            {
                this.m_Curve = new AnimationCurve();
            }
        }

        private void AddPoints(ref List<Vector3> points, float minTime, float maxTime)
        {
            Keyframe keyframe = this.m_Curve[0];
            if (keyframe.time >= minTime)
            {
                Keyframe keyframe2 = this.m_Curve[0];
                points.Add(new Vector3(this.rangeStart, keyframe2.value));
                Keyframe keyframe3 = this.m_Curve[0];
                Keyframe keyframe4 = this.m_Curve[0];
                points.Add(new Vector3(keyframe3.time, keyframe4.value));
            }
            for (int i = 0; i < (this.m_Curve.length - 1); i++)
            {
                Keyframe keyframe5 = this.m_Curve[i + 1];
                if (keyframe5.time >= minTime)
                {
                    Keyframe keyframe6 = this.m_Curve[i];
                    if (keyframe6.time <= maxTime)
                    {
                        Keyframe keyframe7 = this.m_Curve[i];
                        Keyframe keyframe8 = this.m_Curve[i];
                        points.Add(new Vector3(keyframe7.time, keyframe8.value));
                        Keyframe keyframe9 = this.m_Curve[i];
                        Keyframe keyframe10 = this.m_Curve[i + 1];
                        float x = Mathf.Lerp(keyframe9.time, keyframe10.time, 0.001f / ((float) this.m_SegmentResolution));
                        points.Add(new Vector3(x, this.m_Curve.Evaluate(x)));
                        for (float j = 1f; j < this.m_SegmentResolution; j++)
                        {
                            Keyframe keyframe11 = this.m_Curve[i];
                            Keyframe keyframe12 = this.m_Curve[i + 1];
                            x = Mathf.Lerp(keyframe11.time, keyframe12.time, j / ((float) this.m_SegmentResolution));
                            points.Add(new Vector3(x, this.m_Curve.Evaluate(x)));
                        }
                        Keyframe keyframe13 = this.m_Curve[i];
                        Keyframe keyframe14 = this.m_Curve[i + 1];
                        x = Mathf.Lerp(keyframe13.time, keyframe14.time, 1f - (0.001f / ((float) this.m_SegmentResolution)));
                        points.Add(new Vector3(x, this.m_Curve.Evaluate(x)));
                        Keyframe keyframe15 = this.m_Curve[i + 1];
                        x = keyframe15.time;
                        Keyframe keyframe16 = this.m_Curve[i + 1];
                        points.Add(new Vector3(x, keyframe16.value));
                    }
                }
            }
            Keyframe keyframe17 = this.m_Curve[this.m_Curve.length - 1];
            if (keyframe17.time <= maxTime)
            {
                Keyframe keyframe18 = this.m_Curve[this.m_Curve.length - 1];
                Keyframe keyframe19 = this.m_Curve[this.m_Curve.length - 1];
                points.Add(new Vector3(keyframe18.time, keyframe19.value));
                Keyframe keyframe20 = this.m_Curve[this.m_Curve.length - 1];
                points.Add(new Vector3(this.rangeEnd, keyframe20.value));
            }
        }

        public float CalculateLinearTangent(int fromIndex, int toIndex)
        {
            Keyframe keyframe = this.m_Curve[fromIndex];
            Keyframe keyframe2 = this.m_Curve[toIndex];
            Keyframe keyframe3 = this.m_Curve[fromIndex];
            Keyframe keyframe4 = this.m_Curve[toIndex];
            return ((keyframe.value - keyframe2.value) / (keyframe3.time - keyframe4.time));
        }

        public static float[,] CalculateRanges(float minTime, float maxTime, float rangeStart, float rangeEnd, WrapMode preWrapMode, WrapMode postWrapMode)
        {
            WrapMode mode = preWrapMode;
            if (postWrapMode != mode)
            {
                return new float[,] { { rangeStart, rangeEnd } };
            }
            if (mode == WrapMode.Loop)
            {
                if ((maxTime - minTime) > (rangeEnd - rangeStart))
                {
                    return new float[,] { { rangeStart, rangeEnd } };
                }
                minTime = Mathf.Repeat(minTime - rangeStart, rangeEnd - rangeStart) + rangeStart;
                maxTime = Mathf.Repeat(maxTime - rangeStart, rangeEnd - rangeStart) + rangeStart;
                if (minTime < maxTime)
                {
                    return new float[,] { { minTime, maxTime } };
                }
                return new float[,] { { rangeStart, maxTime }, { minTime, rangeEnd } };
            }
            if (mode == WrapMode.PingPong)
            {
                return new float[,] { { rangeStart, rangeEnd } };
            }
            return new float[,] { { minTime, maxTime } };
        }

        public float CalculateSmoothTangent(int index)
        {
            this.m_Curve.SmoothTangents(index, 0f);
            Keyframe keyframe = this.m_Curve[index];
            return keyframe.outTangent;
        }

        public void DrawCurve(float minTime, float maxTime, Color color, Matrix4x4 transform, Color wrapColor)
        {
            Vector3[] points = this.GetPoints(minTime, maxTime);
            DrawCurveWrapped(minTime, maxTime, this.rangeStart, this.rangeEnd, this.preWrapMode, this.postWrapMode, color, transform, points, wrapColor);
        }

        public static void DrawCurveWrapped(float minTime, float maxTime, float rangeStart, float rangeEnd, WrapMode preWrap, WrapMode postWrap, Color color, Matrix4x4 transform, Vector3[] points, Color wrapColor)
        {
            if (points.Length != 0)
            {
                int num;
                int num2;
                if ((rangeEnd - rangeStart) != 0f)
                {
                    num = Mathf.FloorToInt((minTime - rangeStart) / (rangeEnd - rangeStart));
                    num2 = Mathf.CeilToInt((maxTime - rangeEnd) / (rangeEnd - rangeStart));
                }
                else
                {
                    preWrap = WrapMode.Once;
                    postWrap = WrapMode.Once;
                    num = (minTime >= rangeStart) ? 0 : -1;
                    num2 = (maxTime <= rangeEnd) ? 0 : 1;
                }
                int index = points.Length - 1;
                Handles.color = color;
                List<Vector3> list = new List<Vector3>();
                if ((num <= 0) && (num2 >= 0))
                {
                    for (int i = 0; i < points.Length; i++)
                    {
                        Vector3 v = points[i];
                        v = transform.MultiplyPoint(v);
                        list.Add(v);
                    }
                }
                Handles.DrawPolyLine(list.ToArray());
                Handles.color = new Color(wrapColor.r, wrapColor.g, wrapColor.b, wrapColor.a * color.a);
                if (preWrap == WrapMode.Loop)
                {
                    list = new List<Vector3>();
                    for (int j = num; j < 0; j++)
                    {
                        for (int k = 0; k < points.Length; k++)
                        {
                            Vector3 vector2 = points[k];
                            vector2.x += j * (rangeEnd - rangeStart);
                            vector2 = transform.MultiplyPoint(vector2);
                            list.Add(vector2);
                        }
                    }
                    list.Add(transform.MultiplyPoint(points[0]));
                    Handles.DrawPolyLine(list.ToArray());
                }
                else if (preWrap == WrapMode.PingPong)
                {
                    list = new List<Vector3>();
                    for (int m = num; m < 0; m++)
                    {
                        for (int n = 0; n < points.Length; n++)
                        {
                            if ((m / 2) == (((float) m) / 2f))
                            {
                                Vector3 vector3 = points[n];
                                vector3.x += m * (rangeEnd - rangeStart);
                                vector3 = transform.MultiplyPoint(vector3);
                                list.Add(vector3);
                            }
                            else
                            {
                                Vector3 vector4 = points[index - n];
                                vector4.x = (-vector4.x + ((m + 1) * (rangeEnd - rangeStart))) + (rangeStart * 2f);
                                vector4 = transform.MultiplyPoint(vector4);
                                list.Add(vector4);
                            }
                        }
                    }
                    Handles.DrawPolyLine(list.ToArray());
                }
                else if (num < 0)
                {
                    Vector3[] vectorArray1 = new Vector3[] { transform.MultiplyPoint(new Vector3(minTime, points[0].y, 0f)), transform.MultiplyPoint(new Vector3(Mathf.Min(maxTime, points[0].x), points[0].y, 0f)) };
                    Handles.DrawPolyLine(vectorArray1);
                }
                if (postWrap == WrapMode.Loop)
                {
                    list = new List<Vector3> {
                        transform.MultiplyPoint(points[index])
                    };
                    for (int num9 = 1; num9 <= num2; num9++)
                    {
                        for (int num10 = 0; num10 < points.Length; num10++)
                        {
                            Vector3 vector5 = points[num10];
                            vector5.x += num9 * (rangeEnd - rangeStart);
                            vector5 = transform.MultiplyPoint(vector5);
                            list.Add(vector5);
                        }
                    }
                    Handles.DrawPolyLine(list.ToArray());
                }
                else if (postWrap == WrapMode.PingPong)
                {
                    list = new List<Vector3>();
                    for (int num11 = 1; num11 <= num2; num11++)
                    {
                        for (int num12 = 0; num12 < points.Length; num12++)
                        {
                            if ((num11 / 2) == (((float) num11) / 2f))
                            {
                                Vector3 vector6 = points[num12];
                                vector6.x += num11 * (rangeEnd - rangeStart);
                                vector6 = transform.MultiplyPoint(vector6);
                                list.Add(vector6);
                            }
                            else
                            {
                                Vector3 vector7 = points[index - num12];
                                vector7.x = (-vector7.x + ((num11 + 1) * (rangeEnd - rangeStart))) + (rangeStart * 2f);
                                vector7 = transform.MultiplyPoint(vector7);
                                list.Add(vector7);
                            }
                        }
                    }
                    Handles.DrawPolyLine(list.ToArray());
                }
                else if (num2 > 0)
                {
                    Vector3[] vectorArray2 = new Vector3[] { transform.MultiplyPoint(new Vector3(Mathf.Max(minTime, points[index].x), points[index].y, 0f)), transform.MultiplyPoint(new Vector3(maxTime, points[index].y, 0f)) };
                    Handles.DrawPolyLine(vectorArray2);
                }
            }
        }

        public float EvaluateCurveDeltaSlow(float time)
        {
            float num = 0.0001f;
            return ((this.m_Curve.Evaluate(time + num) - this.m_Curve.Evaluate(time - num)) / (num * 2f));
        }

        public float EvaluateCurveSlow(float time)
        {
            return this.m_Curve.Evaluate(time);
        }

        public Bounds GetBounds()
        {
            return this.GetBounds(this.rangeStart, this.rangeEnd);
        }

        public Bounds GetBounds(float minTime, float maxTime)
        {
            Vector3[] points = this.GetPoints(minTime, maxTime);
            float positiveInfinity = float.PositiveInfinity;
            float negativeInfinity = float.NegativeInfinity;
            foreach (Vector3 vector in points)
            {
                if (vector.y > negativeInfinity)
                {
                    negativeInfinity = vector.y;
                }
                if (vector.y < positiveInfinity)
                {
                    positiveInfinity = vector.y;
                }
            }
            if (positiveInfinity == float.PositiveInfinity)
            {
                positiveInfinity = 0f;
                negativeInfinity = 0f;
            }
            return new Bounds(new Vector3((maxTime + minTime) * 0.5f, (negativeInfinity + positiveInfinity) * 0.5f, 0f), new Vector3(maxTime - minTime, negativeInfinity - positiveInfinity, 0f));
        }

        public AnimationCurve GetCurve()
        {
            return this.m_Curve;
        }

        private Vector3[] GetPoints(float minTime, float maxTime)
        {
            List<Vector3> points = new List<Vector3>();
            if (this.m_Curve.length != 0)
            {
                float[,] numArray = CalculateRanges(minTime, maxTime, this.rangeStart, this.rangeEnd, this.preWrapMode, this.postWrapMode);
                for (int i = 0; i < numArray.GetLength(0); i++)
                {
                    this.AddPoints(ref points, numArray[i, 0], numArray[i, 1]);
                }
                if (points.Count > 0)
                {
                    for (int j = 1; j < points.Count; j++)
                    {
                        Vector3 vector = points[j];
                        Vector3 vector2 = points[j - 1];
                        if (vector.x < vector2.x)
                        {
                            points.RemoveAt(j);
                            j--;
                        }
                    }
                }
            }
            return points.ToArray();
        }

        public WrapMode PostWrapMode()
        {
            return this.postWrapMode;
        }

        public WrapMode PreWrapMode()
        {
            return this.preWrapMode;
        }

        public float RangeEnd()
        {
            return this.rangeEnd;
        }

        public float RangeStart()
        {
            return this.rangeStart;
        }

        public void SetCustomRange(float start, float end)
        {
            this.m_CustomRangeStart = start;
            this.m_CustomRangeEnd = end;
        }

        public void SetSegmentSamples(int samples)
        {
            this.m_SegmentResolution = samples;
        }

        public void SetWrap(WrapMode wrap)
        {
            this.preWrapMode = wrap;
            this.postWrapMode = wrap;
        }

        public void SetWrap(WrapMode preWrap, WrapMode postWrap)
        {
            this.preWrapMode = preWrap;
            this.postWrapMode = postWrap;
        }

        private float rangeEnd
        {
            get
            {
                return ((((this.m_CustomRangeStart != 0f) || (this.m_CustomRangeEnd != 0f)) || (this.m_Curve.length <= 0)) ? this.m_CustomRangeEnd : this.m_Curve.keys[this.m_Curve.length - 1].time);
            }
        }

        private float rangeStart
        {
            get
            {
                return ((((this.m_CustomRangeStart != 0f) || (this.m_CustomRangeEnd != 0f)) || (this.m_Curve.length <= 0)) ? this.m_CustomRangeStart : this.m_Curve.keys[0].time);
            }
        }
    }
}

